package com.magold.logic.bulb;

import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.AlphaModifier;
import org.andengine.entity.modifier.IEntityModifier;
import org.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.shape.IAreaShape;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.modifier.IModifier;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.magold.context.IFixedEngine;
import com.magold.logic.ISpriteLogic;
import com.magold.logic.LogicPhysicsHelper;
import com.magold.physics.MagoldPhysicsConnector;

public class BreakerWrapper {
	private final IAreaShape mBreakSprite;
	private final IAreaShape mRect;
	private Body mBody;
	
	public BreakerWrapper(IAreaShape pBreak,final float[] pCoor,Scene pScene, ISpriteLogic pLogic, VertexBufferObjectManager pVbom) {
		mBreakSprite = pBreak;
		mRect = new Rectangle(pCoor[0], pCoor[1], pCoor[2], pCoor[3], pVbom);
		mRect.setUserData(pLogic);
		mRect.setVisible(false);
		pScene.attachChild(mRect);
	}
	
	private void synchronizeDataWithPhycics() {
		mRect.registerUpdateHandler(new IUpdateHandler() {

			@Override
			public void onUpdate(float pSecondsElapsed) {
				if(mBody.getType() == BodyType.StaticBody) return;
				
				float[] centerCoor = mRect.getSceneCenterCoordinates();
				float rotation = mRect.getRotation();

				mBreakSprite.setX(centerCoor[0] - mBreakSprite.getRotationCenterX());
				mBreakSprite.setY(centerCoor[1] - mBreakSprite.getRotationCenterY());
				mBreakSprite.setRotation(rotation);
			}

			@Override
			public void reset() {
				// DO-NOTHING.
			}
			
		});
	}
	
	public MagoldPhysicsConnector connectPhysicsPolygon(PhysicsWorld pWorld, BodyType bodyType, FixtureDef pDef, Vector2[] pCoors) {
		mBody = PhysicsFactory.createPolygonBody(pWorld, mRect, pCoors, bodyType, pDef);
		synchronizeDataWithPhycics();
		return LogicPhysicsHelper.connectBody(pWorld, mBody, mRect);
	}
	
	public MagoldPhysicsConnector connectPhycicsWithBox(PhysicsWorld pWorld, BodyType bodyType, FixtureDef pDef) {
		mBody = PhysicsFactory.createBoxBody(pWorld, mRect, bodyType, pDef);
		synchronizeDataWithPhycics();
		return LogicPhysicsHelper.connectBody(pWorld, mBody, mRect);
	}
	
	public void setVisible(boolean pIsVisible) {
		mBreakSprite.setVisible(pIsVisible);
	}

	public void registerEntityModifier(IEntityModifier pModifier) {
		mBreakSprite.registerEntityModifier(pModifier);
	}

	public float[] getSceneCenterCoordinates() {
		return mRect.getSceneCenterCoordinates();
	}

	public void registerSelfDestroy(final BulbBreaker pBreaker, final float pLifeCycle,
			final PhysicsWorld pWorld, final IFixedEngine pEngine) {
		mBreakSprite.registerUpdateHandler(new IUpdateHandler() {
			private float mElapsedSeconds;
			@Override
			public void onUpdate(float pSecondsElapsed) {
				if(mElapsedSeconds >= pLifeCycle){
					if(mBody.isAwake()) return;
					
					PhysicsConnector breakConnector = pBreaker.findPhysicsConnector(mRect);
					
					pWorld.unregisterPhysicsConnector(breakConnector);
					pWorld.destroyBody(breakConnector.getBody());
					pEngine.unregisterChildFromScene(mRect);
					
					disappearModifier(pEngine);
					mBreakSprite.unregisterUpdateHandler(this);
				} else {
					mElapsedSeconds += pSecondsElapsed;
				}
			}
			
			@Override
			public void reset() { }
		});
	}

	protected void disappearModifier(final IFixedEngine pEngine) {
		IEntityModifierListener listener = new IEntityModifierListener() {
			@Override
			public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) { }
			@Override
			public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
				pEngine.unregisterChildFromScene(mBreakSprite);
			}
		};
		AlphaModifier modifier = new AlphaModifier(1.0f, 1.0f, 0.0f, listener);
		mBreakSprite.registerEntityModifier(modifier);
	}

	public boolean sameWith(IAreaShape pShape) {
		return pShape == mRect;
	}
}
